package org.example.me.handler.template;

import lombok.extern.slf4j.Slf4j;
import org.example.me.entity.ExcelLog;
import org.example.me.enums.ExcelTypeEnum;
import org.example.me.handler.context.ExcelContext;
import org.example.me.util.ZipCompressor;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
 * Excel导出基础模板抽象类
 * 定义了Excel导出的基本流程和通用方法，包括文件生成、压缩和上传等操作
 * 具体的写文件操作由子类实现
 * 
 * 该类提供了导出流程的统一管理，包括：
 * 1. 初始化导出上下文
 * 2. 执行具体的写文件操作（由子类实现）
 * 3. 压缩生成的文件
 * 4. 模拟上传操作
 */
@Slf4j
public abstract class AbstractBaseExcelExportTemplate implements ExcelExport {
    /**
     * 临时文件存储根路径
     */
    protected static final String PATH_SOURCE = System.getProperty("user.dir") + "/temp/file/";

    /**
     * ZIP压缩文件存储路径
     */
    protected static final String PATH_ZIP = PATH_SOURCE + "zip/";

    /**
     * Excel导出主流程方法
     * 定义了完整的导出流程：初始化上下文 -> 写入文件 -> 压缩 -> 上传
     *
     * @param excelLog Excel导出日志信息
     * @return 文件访问URL
     */
    @Override
    public final String export(ExcelLog excelLog) {
        String url = null;
        try {
            ExcelTypeEnum excelType = getExcelType();
            String fileName = excelType.getFileName();
            // 解析参数获取要导出的数据
            ExcelContext excelContext = new ExcelContext();
            excelContext.setExcelLog(excelLog);
            excelContext.setTempDirectory(getTempDirectory(excelLog));
            excelContext.setZipName(getZipName(fileName));
            writeFile(excelContext);

            // 压缩生成的Excel文件
            zip(excelContext);
            // 模拟上传操作，获取文件访问URL
            url = upload(excelContext);
        } catch (Exception e) {
            log.error("Excel导出失败: {}", e.getMessage(), e);
            throw new RuntimeException("Excel导出失败", e);
        }
        return url;
    }

    /**
     * 抽象方法，由子类实现具体的写文件操作
     *
     * @param excelContext Excel上下文信息
     */
    protected abstract void writeFile(ExcelContext excelContext);

    /**
     * 初始化用户导出临时目录
     * 生成目录 : PATH_SOURCE / 按模板ID/导出用户ID/任务ID
     *
     * @param excelContext Excel上下文信息
     * @return 用户文件目录路径
     */
    protected static String initUserTempDirectory(ExcelContext excelContext) {
        String userFileDirectoryPath = excelContext.getTempDirectory();
        File directory = new File(userFileDirectoryPath);
        File directoryZip = new File(PATH_ZIP);
        if (!directoryZip.exists()) {
            boolean success = directoryZip.mkdirs();
            if (!success) {
                log.error("Failed to create zip directory.");
            }
        }
        if (!directory.exists()) {
            boolean success = directory.mkdirs();
            if (!success) {
                log.error("Failed to create directory.");
            }
        }
        return userFileDirectoryPath;
    }

    /**
     * 获取临时目录路径
     *
     * @param excelLog Excel日志信息
     * @return 临时目录路径
     */
    protected final String getTempDirectory(ExcelLog excelLog) {
        return PATH_SOURCE + excelLog.getType() + "/" + UUID.randomUUID();
    }

    /**
     * 生成ZIP文件名
     *
     * @param fileName 原始文件名
     * @return ZIP文件名（包含时间戳）
     */
    private String getZipName(String fileName) {
        return String.format("%s-%s.zip", fileName, LocalDateTime.now().format(DateTimeFormatter.ofPattern("MMddHHmmss")));
    }

    /**
     * 将导出的文件压缩为ZIP格式
     *
     * @param excelContext Excel上下文信息
     */
    private void zip(ExcelContext excelContext) {
        try {
            if (excelContext.isNeedCompress()) {
                String directory = excelContext.getTempDirectory();
                String zipName = excelContext.getZipName();
                ZipCompressor.compressToZip(directory, PATH_ZIP + "/" + zipName);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 模拟文件上传操作
     *
     * @param excelContext Excel上下文信息
     * @return 文件访问路径
     */
    private String upload(ExcelContext excelContext) {
        List<String> uploadFileList = new ArrayList<>();
        // 根据needCompress标志决定上传压缩文件还是原始文件
        if (excelContext.isNeedCompress()) {
            uploadFileList.add(String.format("%s/%s", PATH_ZIP, excelContext.getZipName()));
        } else {
            // 如果不压缩，则上传第一个生成的文件
            List<String> fileList = excelContext.getTempFileList();
            if (fileList != null && !fileList.isEmpty()) {
                uploadFileList.addAll(fileList);
            }
        }
        if (uploadFileList.isEmpty()) {
            return "";
        }
        // 上传文件操作
        // 模拟上传操作，返回文件访问路径
        // 删除临时压缩文件
        if (excelContext.isNeedRemoveTemp()) {
            uploadFileList.forEach(filePath -> {
                File file = new File(filePath);
                if (file.exists()) {
                    file.delete();
                }
            });
        }
        return String.join(",", uploadFileList);
    }

    /**
     * 向Excel上下文中添加文件路径
     *
     * @param excelContext Excel上下文信息
     * @param filePath     文件路径
     */
    protected static void addFile(ExcelContext excelContext, String filePath) {
        List<String> strings = Optional.ofNullable(excelContext.getTempFileList()).orElseGet(ArrayList::new);
        strings.add(filePath);
        excelContext.setTempFileList(strings);
    }

}